package penguin.rpc;

import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import penguin.common.Constants;
import penguin.exception.PenguinException;
import penguin.rpc.dto.RpcDTO;
import penguin.transfer.TransferClient;
import penguin.transfer.TransferClientFactory;
import penguin.transfer.TransferListener;

import java.util.ArrayList;
import java.util.List;

/**
 * Created on 15/7/4 上午11:34
 *
 * @author 王建华(penguin83@126.com)
 */
public  class RpcClient implements TransferListener{

    private static final Logger LOGGER = LoggerFactory.getLogger(RpcClient.class);

    private TransferClient transferClient;

    //当前连接地址的地址
    private String currentHost;
    //当前连接地址的端口
    private int  currentPort;

    //缓存的项目的地址列表  格式 ip:port
    private List<String> addressList = new ArrayList<String>();
    private int currentIndex = -1;

    private String remoteProjectName;

    private RegisterClient registerClient;

    private void nextAddress(){
        this.currentIndex = (currentIndex+1)%addressList.size();
        String[] address = addressList.get(currentIndex).split(":");
        currentHost = address[0];
        currentPort = Integer.valueOf(address[1]);
    }

    /**
     * 重连的具体方法
     */
    protected void connect(){

        if(transferClient != null && transferClient.isConnected()){
           return;
        }
        nextAddress();
        LOGGER.debug("[" + currentHost + ":" + currentPort + "] connect");
        transferClient = TransferClientFactory.buildNetty(currentHost, currentPort, this);
        transferClient.connect();
    }


    /**
     * 简单的直连方式
     */
    public void initDirect(){
        connect();
    }

    /**
     * 启动后 在registerClient 注册，register周期性刷新项目列表
     * @return
     */
    public void init(){
        registerClient.registerRemoteProject(remoteProjectName,this);
    }


    /**
     *  同步调用方法
     */
    public Object execSync(String serviceName,String methodName,Object... params) throws Exception {

        RpcDTO rpcDTO = new RpcDTO(serviceName,methodName,params);

        Object object = null;

        try {
            object = transferClient.sendSync(rpcDTO);
        } catch (Exception e) {
            LOGGER.error("远程调用失败:"+e.getLocalizedMessage());
            throw  e;
        }

        return object;
    }

    public void connected(String hostAddress, int port) {

    }

    /**
     * 断开后重连
     */
    public void disConnected(String hostAddress, int port) {
        LOGGER.error("[" + hostAddress + ":" + port + "] disconnect");
        try {
            Thread.sleep(Constants.RETRY_TIME);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        connect();
    }

    public void receiveMessage(Channel channel, Object message) {

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
        LOGGER.debug("[" + currentHost + ":" + currentPort + "] exceptionCaught ");
        try {
            Thread.sleep(Constants.RETRY_TIME);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        connect();
    }

    public String getCurrentHost() {
        return currentHost;
    }

    public void setCurrentHost(String currentHost) {
        this.currentHost = currentHost;
    }

    public int getCurrentPort() {
        return currentPort;
    }

    public void setCurrentPort(int currentPort) {
        this.currentPort = currentPort;
    }

    public List<String> getAddressList() {
        return addressList;
    }

    public void setAddressList(List<String> addressList) {
        this.addressList = addressList;
    }

    public int getCurrentIndex() {
        return currentIndex;
    }

    public void setCurrentIndex(int currentIndex) {
        this.currentIndex = currentIndex;
    }

    public String getRemoteProjectName() {
        return remoteProjectName;
    }

    public void setRemoteProjectName(String remoteProjectName) {
        this.remoteProjectName = remoteProjectName;
    }

    public RegisterClient getRegisterClient() {
        return registerClient;
    }

    public void setRegisterClient(RegisterClient registerClient) {
        this.registerClient = registerClient;
    }
}
